import { CacheService } from '@app/cache';
import { ChargeOrder } from '@app/db/entities/ChargeOrder';
import { ChargingCard } from '@app/db/entities/ChargingCard';
import { ChargingCardLog } from '@app/db/entities/ChargingCardLog';
import { ChargingStation } from '@app/db/entities/ChargingStation';
import { ChargingStationDailyIncome } from '@app/db/entities/ChargingStationDailyIncome';
import { Device } from '@app/db/entities/Device';
import { Merchant } from '@app/db/entities/Merchant';
import { MerchantDailyIncome } from '@app/db/entities/MerchantDailyIncome';
import { Platform } from '@app/db/entities/Platform';
import { PlatformDailyIncome } from '@app/db/entities/PlatformDailyIncome';
import { PricingFastCharge } from '@app/db/entities/PricingFastCharge';
import { PricingSlowCharge } from '@app/db/entities/PricingSlowCharge';
import { UtilsService } from '@app/utils';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AliIotService } from 'apps/ali-iot/src/ali-iot.service';
import { DataSource, Repository } from 'typeorm';

@Injectable()
export class ChargeCardOrderService {
    constructor(
        @InjectRepository(ChargeOrder) public chargeOrder:Repository<ChargeOrder>,
        @InjectRepository(Merchant) public merchant:Repository<Merchant>,
        @InjectRepository(Device) public device:Repository<Device>,
        @InjectRepository(ChargingStation) public chargingStation:Repository<ChargingStation>,
        @InjectRepository(ChargingCard) public chargingCard:Repository<ChargingCard>,
        @InjectRepository(ChargingCardLog) public chargingCardLog:Repository<ChargingCardLog>,
        @InjectRepository(PricingFastCharge) public pricingFastCharge:Repository<PricingFastCharge>,
        @InjectRepository(PricingSlowCharge) public pricingSlowCharge:Repository<PricingSlowCharge>,
        private cache:CacheService,
        protected dataSource: DataSource,
        private readonly aliIot:AliIotService,
        private readonly utils:UtilsService,
    ){

    }

    public generateOrderNo(userId:number) {
        const date = new Date()
        const time = Math.floor(date.getTime() / 1000) % 1000000
        const year = date.getFullYear() % 100
        const month = String(date.getMonth() + 1).padStart(2, '0')
        const day = String(date.getDate()).padStart(2, '0')
        return year + month + day + time + String(userId).padStart(10, '0')
    }

    async order(msg:any) {
        const port = msg.port
        const cardNo = msg.cardID
        const deviceId = Number(msg.id)
        const mode = msg.chargeMode

        const resMsg:any = {
            type : 16,
            event : msg.event,
            port,
            cardID : cardNo,
            order : '0',
            msgId : '0',
            s : 0
        }

        const lockKey = 'card:c:' + cardNo
        const lock = await this.cache.set(lockKey, '1', 10, 'NX')
        if(!lock) return null

        const device = await this.device.findOne({
            where : {id : deviceId},
            select : ['chargeType', 'stationId', 'owners', 'aliProduct']
        })
        
        let chargeNumber = 0 //可以充多少

        let amount = 0 //要支付的金额
        let unitPrice = 0 //电价单价
        let unitService = 0 //服务费单价
        let kwh = 0 //可以充多少度电

        let pricing;

        const station = await this.chargingStation.findOne({
            where : {id : device.stationId},
            select : ['fastPricing', 'slowPricing']
        })


        if(device.chargeType == 1) {

        }else { //慢充
            if(station.slowPricing == 0) return null

            pricing = await this.pricingSlowCharge.findOne({
                where : {id : station.slowPricing}
            })


            if(!pricing) {
                return null
            }

            unitPrice = Number(pricing.price)
            unitService = Number(pricing.service)
        }

        

        let date = new Date()

        let order:{[k in keyof ChargeOrder]? : ChargeOrder[k]} = {
            //orderNo,
            payType : 2,
            //cardId : card.id,
            clientSource : 3,
            createTime : Math.floor(date.getTime() / 1000),
            unitPrice :  String(unitPrice),
            unitService : String(unitService),
            status : 1,
            deviceId,
            //precharge : chargeNumber,
            //userId,
            port : port,
            feeType : mode,
            //chargeAmount : String(amount),
            feeAmount : '0',
            feeRewardAmount : '0'
        }

        if(device.owners != null && device.owners.length > 0) {
            order.merchantId = device.owners[0]
            const merchant = await this.merchant.findOne({
                where : {id : order.merchantId},
                select : ['profitRate']
            })

            if(merchant != null) {
                order.profitRate = merchant.profitRate
            }
        }

        if(device.stationId > 0) {
            order.stationId = device.stationId
        }

        

        const queryRunner = await this.dataSource.createQueryRunner()
        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {
            let orderId = 0
            order.payStatus = 1

            let card = await queryRunner.manager.findOne<ChargingCard>(ChargingCard, {
                where : {cardNo : String(cardNo)},
                select : ['amount', 'rewardAmount', 'id', 'status', 'userId'],
                lock : {
                    mode : 'pessimistic_read'
                }
            })


            if(card == null || card.status != 1) {
                this.aliIot.pubToDevice(deviceId, device.aliProduct, resMsg)
                await queryRunner.rollbackTransaction();
                return -1
            }

            let rechargeBalance = Number(card.amount) //充值的余额
            let rewardBalance = Number(card.rewardAmount) //赠送的余额
            amount = Number((rechargeBalance + rewardBalance).toFixed(2))
            if(amount < 0.01) {
                this.aliIot.pubToDevice(deviceId, device.aliProduct, resMsg)
                await queryRunner.rollbackTransaction();
                return -2
            }

            kwh = Number((amount / (unitPrice + unitService)).toFixed(2)) //可以充多少度电
            
            if(kwh < 0.01) {
                this.aliIot.pubToDevice(deviceId, device.aliProduct, resMsg)
                return
            }

            resMsg.kwh = kwh

            if(mode == 0) { //时间
                chargeNumber = kwh / pricing.hourKwh
            }else if(mode == 1){
                chargeNumber = kwh
            }

            console.log('kwh:' + kwh)

            console.log('kwh:' + kwh)
            console.log('chargeNumber:' + chargeNumber)


            order.orderNo = this.generateOrderNo(card.userId)
            order.precharge = chargeNumber
            order.chargeAmount = String(amount)

            order.cardId = card.id
            order.userId = card.userId
            order.feeAmount = card.amount
            order.feeRewardAmount = card.rewardAmount


            const cardUpdate:{[key in keyof ChargingCard]? : ChargingCard[key]} = {}
            const log:{[key in keyof ChargingCardLog]? : ChargingCardLog[key]} = {
                cardId : card.id,
                userId : card.userId,
                amount : card.amount,
                rewardAmount : card.rewardAmount,
                beforeAmount : card.amount,
                beforeRewardAmount : card.rewardAmount,
                afterAmount : '0',
                afterRewardAmount : '0',
                type : 2
            }

            if(rechargeBalance > 0) {
                cardUpdate.amount = '0'
            }
            if(rewardBalance > 0) {
                cardUpdate.rewardAmount = '0'
            }


            //更新卡的余额
            const r1 = await queryRunner.manager.update<ChargingCard>(ChargingCard, { id : card.id }, cardUpdate)
            if(r1.affected < 1) {
                await queryRunner.rollbackTransaction();
                return -2
            }


            console.log(order)
            

            //加入订单
            const r2 = await queryRunner.manager.insert<ChargeOrder>(ChargeOrder, order)
            if(!r2.raw || r2.raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return -3
            }
            log.relationId = orderId = r2.raw.insertId


            //加入钱包明细
            log.createTime = order.createTime
            const { raw } = await queryRunner.manager.insert<ChargingCardLog>(ChargingCardLog, log)
            if(!raw || raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return -4
            }

            resMsg.order = String(orderId).padStart(16, '0')
            resMsg.msgId = resMsg.order.padStart(32, '0')
            resMsg.s = 1

            const res = await this.aliIot.pubToDevice(deviceId, device.aliProduct, resMsg)
            if(!res || !res.body || !res.body.success) {
                await queryRunner.rollbackTransaction();
                return -5
            }


            await queryRunner.commitTransaction();

            return orderId

        } catch (error) {
            console.log(error)
            await queryRunner.rollbackTransaction();
            return null
        } finally {
            this.cache.del(lockKey)
            await queryRunner.release();
        }
    }


    async settle(orderId:number, chargeTime:number, kwh:number, maxPower:number, reason:number) {
        //Number(msg.order), msg.chargeTime, msg.chargequantity, msg.maxPower, msg.y
        if(isNaN(orderId)) return
        console.log('结算' + orderId)
        const order = await this.chargeOrder.findOne({
            where : {id : orderId},
            //select : ['status', 'unitPrice', 'unitService', 'userId']
        })

        if(!order || order.status != 1) return

        const currentDate = new Date();  
        const todayStartTime = Math.floor(currentDate.setHours(0, 0, 0, 0) / 1000);
    
        const time = Math.floor(currentDate.getTime() / 1000)

        //amount是总的收益
        const amount = Number(((Number(order.unitPrice) + Number(order.unitService)) * kwh).toFixed(2))
        let updateData:{[key in keyof ChargeOrder]? : ChargeOrder[key]} = {stopReason : reason, status : 2, endTime : Math.floor(Date.now() / 1000), consumeAmount : String(amount), consumeKwh : kwh, chargeData : {time : chargeTime, maxPower : maxPower}}

        let platformProfit = amount

        const queryRunner = await this.dataSource.createQueryRunner()
        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {

            const offsetAmount = Number((Number(order.chargeAmount) - Number(amount)).toFixed(2)) //看看剩余多少钱
            if(offsetAmount > 0) { //有钱剩
                //看看先退充值余额，还是赠送余额
                const feeAmount = Number(order.feeAmount)
                const feeRewardAmount = Number(order.feeRewardAmount)

                let _feeAmount = 0 //要退的
                let _feeRewardAmount = 0 //要退的
                if(offsetAmount <= feeRewardAmount) { //剩余的钱全部退到赠送的余额
                    _feeRewardAmount = offsetAmount
                }else {
                    _feeRewardAmount = feeRewardAmount
                    _feeAmount = offsetAmount - feeRewardAmount
                }

                let card = await queryRunner.manager.findOne<ChargingCard>(ChargingCard, {
                    where : {id : order.cardId},
                    select : ['amount', 'rewardAmount'],
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })


                let log:{[key in keyof ChargingCardLog]? : ChargingCardLog[key]} = {
                    userId : order.userId,
                    cardId : order.cardId,
                    type : 3,
                    relationId : orderId,
                    createTime : time,
                    beforeAmount : card.amount,
                    beforeRewardAmount : card.rewardAmount,
                }

                if(_feeAmount > 0) {
                    log.afterAmount = card.amount = (Number(card.amount) + _feeAmount).toFixed(2)
                    order.feeAmount = (feeAmount - _feeAmount).toFixed(2)
                    log.amount = String(_feeAmount)
                }else {
                    log.afterAmount = card.amount
                }


                if(_feeRewardAmount > 0) {
                    log.afterRewardAmount = card.rewardAmount = (Number(card.rewardAmount) + _feeRewardAmount).toFixed(2)
                    order.feeRewardAmount = (feeRewardAmount - _feeRewardAmount).toFixed(2)

                    log.rewardAmount = String(_feeRewardAmount)
                }else {
                    log.afterRewardAmount = card.rewardAmount
                }
                

                //更新卡余额
                const r1 = await queryRunner.manager.update<ChargingCard>(ChargingCard, { id : order.cardId }, card)
                if(r1.affected < 1) {
                    await queryRunner.rollbackTransaction();
                    return -2
                }

                

                //加入钱包明细
                const { raw } = await queryRunner.manager.insert<ChargingCardLog>(ChargingCardLog, log)
                if(!raw || raw.affectedRows < 1) {
                    await queryRunner.rollbackTransaction();
                    return -4
                }
            }

            //更新订单
            const r2 = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { id : orderId }, updateData)
            if(r2.affected < 1) {
                await queryRunner.rollbackTransaction();
                return -2
            }

            if(amount > 0) {
                let merchantProfit = 0
                if(order.merchantId > 0) {
                    //这是运营商分到的钱
                    merchantProfit = this.utils.round(amount * Number(order.profitRate) / 100, 2)//Number((amount * Number(order.profitRate) / 100).toFixed(2))
                    if(merchantProfit > 0) {
                    platformProfit = Number((amount - merchantProfit).toFixed(2))
                    }
                    
        
                    let merchant = await queryRunner.manager.findOne<Merchant>(Merchant, {
                        where : {id : order.merchantId},
                        select : ['amount', 'totalChargeOrderCount', 'totalChargeAmount', 'totalChargeKwh', 'totalChargeTime'],
                        lock : {
                            mode : 'pessimistic_read'
                        }
                    })
        
                    const r3 = await queryRunner.manager.update<Merchant>(Merchant, { id : order.merchantId }, {
                    amount : (Number(merchant.amount) + merchantProfit).toFixed(2),
                    totalChargeAmount : (Number(merchant.totalChargeAmount) + merchantProfit).toFixed(2),
                    totalChargeKwh : merchant.totalChargeKwh + kwh,
                    totalChargeTime : merchant.totalChargeTime + chargeTime,
                    totalChargeOrderCount : merchant.totalChargeOrderCount + 1
                    })
                    if(r3.affected < 1) {
                        await queryRunner.rollbackTransaction();
                        return -4
                    }
        
                    //加入商户每天收入记录
                    const log = await queryRunner.manager.findOne<MerchantDailyIncome>(MerchantDailyIncome, {
                    where : {merchantId : order.merchantId, date :todayStartTime},
                    select : ['id', 'amount', 'kwh', 'time', 'chargeOrderCount']
                    })
                    if(log == null) {
                    const { raw } = await queryRunner.manager.insert<MerchantDailyIncome>(MerchantDailyIncome, {
                        merchantId : order.merchantId,
                        date : todayStartTime,
                        amount : String(merchantProfit),
                        kwh : kwh,
                        time : chargeTime,
                        chargeOrderCount : 1
                    })
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction();
                        return -4
                    }
                    }else {
                    const r4 = await queryRunner.manager.update<MerchantDailyIncome>(MerchantDailyIncome, { id : log.id }, {
                        amount : (Number(log.amount) + merchantProfit).toFixed(2),
                        kwh : log.kwh + kwh,
                        time : log.time + chargeTime,
                        chargeOrderCount : log.chargeOrderCount + 1
                    })
                    if(r4.affected < 1) {
                        await queryRunner.rollbackTransaction();
                        return -4
                    }
                    }
                }
        
                //站点
                if(order.stationId > 0) {
                    let station = await queryRunner.manager.findOne<ChargingStation>(ChargingStation, {
                        where : {id : order.stationId},
                        select : ['totalChargeAmount', 'totalChargeKwh', 'totalChargeOrderCount', 'totalChargeTime'],
                        lock : {
                            mode : 'pessimistic_read'
                        }
                    })
        
                    if(station != null) {
                    const r3 = await queryRunner.manager.update<ChargingStation>(ChargingStation, { id : order.stationId }, {
                        totalChargeAmount : (Number(station.totalChargeAmount) + merchantProfit).toFixed(2),
                        totalChargeKwh : station.totalChargeKwh + kwh,
                        totalChargeTime : station.totalChargeTime + chargeTime,
                        totalChargeOrderCount : station.totalChargeOrderCount + 1
                    })
                    if(r3.affected < 1) {
                        await queryRunner.rollbackTransaction();
                        return -4
                    }
            
                    //加入站带你每天收入记录
                    const log = await queryRunner.manager.findOne<ChargingStationDailyIncome>(ChargingStationDailyIncome, {
                        where : {stationId : order.stationId, date :todayStartTime},
                        select : ['id', 'amount', 'kwh', 'time', 'chargeOrderCount']
                    })
                    if(log == null) {
                        const { raw } = await queryRunner.manager.insert<ChargingStationDailyIncome>(ChargingStationDailyIncome, {
                        stationId : order.stationId,
                        date : todayStartTime,
                        amount : String(merchantProfit),
                        kwh : kwh,
                        time : chargeTime,
                        chargeOrderCount : 1
                        })
                        if(!raw || raw.affectedRows < 1) {
                            await queryRunner.rollbackTransaction();
                            return -4
                        }
                    }else {
                        const r4 = await queryRunner.manager.update<ChargingStationDailyIncome>(ChargingStationDailyIncome, { id : log.id }, {
                        amount : (Number(log.amount) + merchantProfit).toFixed(2),
                        kwh : log.kwh + kwh,
                        time : log.time + chargeTime,
                        chargeOrderCount : log.chargeOrderCount + 1
                        })
                        if(r4.affected < 1) {
                            await queryRunner.rollbackTransaction();
                            return -4
                        }
                    }
                    }
        
                    
                }
        
        
                //平台入账
                let platform = await queryRunner.manager.findOne<Platform>(Platform, {
                    where : {id : 1},
                    select : ['totalChargeOrderCount', 'totalAmount', 'totalProfit', 'totalKwh', 'totalTime', 'id'],
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })
                const r5 = await queryRunner.manager.update<Platform>(Platform, { id : platform.id }, {
                    totalAmount : (Number(platform.totalAmount) + amount).toFixed(2),
                    totalProfit : (Number(platform.totalProfit) + platformProfit).toFixed(2),
                    totalKwh : platform.totalKwh + kwh,
                    totalTime : platform.totalTime + chargeTime,
                    totalChargeOrderCount : platform.totalChargeOrderCount + 1
                })
                if(r5.affected < 1) {
                    await queryRunner.rollbackTransaction();
                    return -5
                }
        
                //加入平台每天收入记录
                const log = await queryRunner.manager.findOne<PlatformDailyIncome>(PlatformDailyIncome, {
                    where : {date :todayStartTime},
                    select : ['id', 'amount', 'kwh', 'time', 'profit', 'chargeOrderCount']
                })
                if(log == null) {
                    const { raw } = await queryRunner.manager.insert<PlatformDailyIncome>(PlatformDailyIncome, {
                    date : todayStartTime,
                    amount : String(amount),
                    profit : String(platformProfit),
                    kwh : kwh,
                    time : chargeTime,
                    chargeOrderCount : 1
                    })
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction();
                        return -6
                    }
                }else {
                    const r6 = await queryRunner.manager.update<PlatformDailyIncome>(PlatformDailyIncome, { id : log.id }, {
                    amount : (Number(log.amount) + amount).toFixed(2),
                    profit : (Number(log.profit) + platformProfit).toFixed(2),
                    kwh : log.kwh + kwh,
                    time : log.time + chargeTime,
                    chargeOrderCount : log.chargeOrderCount + 1
                    })
                    if(r6.affected < 1) {
                        await queryRunner.rollbackTransaction();
                        return -4
                    }
                }
        
            }

            await queryRunner.commitTransaction()
            console.log('结算完成')
            
        } catch (error) {
            console.log(error)
            await queryRunner.rollbackTransaction();
          } finally {
            await queryRunner.release();
          }
    }
}
